return cpu_frequency_change(this_cpu(freq));
}
-static long cpu_down_helper(void *data)
-{
- int cpu = (unsigned long)data;
- return cpu_down(cpu);
-}
+/* from sysctl.c */
+long cpu_up_helper(void *data);
+long cpu_down_helper(void *data);
ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
{
case XENPF_cpu_online:
{
- int cpu;
+ int cpu = op->u.cpu_ol.cpuid;
- cpu = op->u.cpu_ol.cpuid;
- if (!cpu_present(cpu))
+ if ( !cpu_present(cpu) )
{
ret = -EINVAL;
break;
}
- else if (cpu_online(cpu))
+
+ if ( cpu_online(cpu) )
{
ret = 0;
break;
}
- ret = cpu_up(cpu);
+ ret = continue_hypercall_on_cpu(
+ 0, cpu_up_helper, (void *)(unsigned long)cpu);
break;
}
case XENPF_cpu_offline:
{
- int cpu;
+ int cpu = op->u.cpu_ol.cpuid;
- cpu = op->u.cpu_ol.cpuid;
- if (!cpu_present(cpu))
+ if ( !cpu_present(cpu) )
{
ret = -EINVAL;
break;
- } else if (!cpu_online(cpu))
+ }
+
+ if ( !cpu_online(cpu) )
{
ret = 0;
break;
}
+
ret = continue_hypercall_on_cpu(
- 0, cpu_down_helper, (void *)(unsigned long)cpu);
+ 0, cpu_down_helper, (void *)(unsigned long)cpu);
break;
}
break;
#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0)
-static long cpu_down_helper(void *data)
+long cpu_up_helper(void *data)
{
int cpu = (unsigned long)data;
- return cpu_down(cpu);
+ int ret = cpu_up(cpu);
+ if ( ret == -EBUSY )
+ {
+ /* On EBUSY, flush RCU work and have one more go. */
+ rcu_barrier();
+ ret = cpu_up(cpu);
+ }
+ return ret;
+}
+
+long cpu_down_helper(void *data)
+{
+ int cpu = (unsigned long)data;
+ int ret = cpu_down(cpu);
+ if ( ret == -EBUSY )
+ {
+ /* On EBUSY, flush RCU work and have one more go. */
+ rcu_barrier();
+ ret = cpu_down(cpu);
+ }
+ return ret;
}
extern int __node_distance(int a, int b);
switch ( sysctl->u.cpu_hotplug.op )
{
case XEN_SYSCTL_CPU_HOTPLUG_ONLINE:
- ret = cpu_up(cpu);
+ ret = continue_hypercall_on_cpu(
+ 0, cpu_up_helper, (void *)(unsigned long)cpu);
break;
case XEN_SYSCTL_CPU_HOTPLUG_OFFLINE:
ret = continue_hypercall_on_cpu(